//
// Created by snake on 2022/11/8.
//

#include <tuple>
#include <fstream>
#include <string>
#include <optional>
#include <vector>
#include <fmt/core.h>
#include <map>

#include "arg.hpp"
#include "file.hpp"


using namespace std;
namespace fs = filesystem;

/**
 * 计算单个文件行数信息
 * @param filename
 * @return 非空行数, 空行数, 总行数
 */
optional<tuple<int, int, int>> cnt_line(const string &filename) {
    int nblank_cnt = 0, blank_cnt = 0;
    ifstream ifs(filename);
    if (!ifs.is_open()) {
        fmt::print("can't open {}", filename);
        return nullopt;
    }
    string buf;
    while (getline(ifs, buf)) {
        //  不同系统空行不同
#ifdef _WIN32
        buf.empty()
#else
        buf == "\r"
        #endif
        ? blank_cnt++ : nblank_cnt++;
        // fmt::print("n{} b{}\t{}\n", nblank_cnt, blank_cnt, buf);
    }

    // 最后空行不会计算
    blank_cnt += buf.empty();

    return make_tuple(nblank_cnt, blank_cnt, nblank_cnt + blank_cnt);
}

void format_print(vector<string> &file_list, map<string, tuple<int, int, int>> &lines_list, Args &args) {
    cout << "line\tfile" << endl;
    cout << "----\t----" << endl;
    if (file_list.size() == 1) {
        string file_name = file_list[0];
        auto [nblank_cnt, blank_cnt, total] = lines_list.find(file_name)->second;
        if (args.ignore_blank)
            // cout << nblank_cnt << "\t" << file_name << endl;
            fmt::print("{}\t{}\n", nblank_cnt, file_name);
        else
            cout << setw(4) << total << "\t" << file_name << endl;
        return;
    }
    int total = 0;
    for (auto it = file_list.begin(); it != file_list.end(); it++) {
        auto [nblank_cnt, blank_cnt, total_] = lines_list.at(*it);
        if (args.all) {
            total += total_;
            continue;
        } else if (args.ignore_blank) {
            cout << setw(4) << nblank_cnt << "\t" << *it << endl;
            total += nblank_cnt;
            continue;
        } else {
            cout << setw(4) << total_ << "\t" << *it << endl;
            total += total_;
            continue;
        }
    }
    cout << setw(4) << total << "\ttotal" << endl;
}

int main(int argc, char *argv[]) {
    auto args = parse_args(argc, argv);

//    fmt::print("all: {}, recursive: {}, ignore: {}, suffix: {}\n",
//               args.all, args.recursive, args.ignore_blank, args.suffix);

    // 文件清单
    auto file_list = vector<string>();
    for (int i = optind; i < argc; ++i) {
        string filename = argv[i];
        switch (fs::status(filename).type()) {
            case fs::file_type::regular:
                if (filename.ends_with(args.suffix)) {
                    file_list.emplace_back(filename);
                }
                break;
            case fs::file_type::directory:
                if (args.recursive) {
                    getfilelist_r(filename, file_list, args.suffix);
                } else {
                    for (auto &p: fs::directory_iterator(filename)) {
                        auto pth = p.path().string();
                        if (fs::is_regular_file(p) && pth.ends_with(args.suffix)) {
                            file_list.emplace_back(pth);
                        }
                    }
                }
                break;
            default:
                break;
        }
    }

    map<string, tuple<int, int, int>> lines_list;
    for (const auto &item: file_list) {
        auto lines_record = *cnt_line(item);
        auto [nblank_cnt, blank_cnt, total] = lines_record;
        lines_list.insert(make_pair(item, lines_record));
//        fmt::print("{} :n{} b{} t{}\n", item, nblank_cnt, blank_cnt, total);
    }
    format_print(file_list, lines_list, args);
    return 0;
}
